package com.victor.bookretail.service;

import cn.hutool.json.JSONUtil;
import com.victor.bookretail.common.ResultCode;
import com.victor.bookretail.domain.OrderInfoBo;
import com.victor.bookretail.domain.PointCalculateParameter;
import com.victor.bookretail.domain.UserInfoBo;
import com.victor.bookretail.domain.UserInfoSearchBo;
import com.victor.bookretail.entity.UserInfoPo;
import com.victor.bookretail.exception.BusinessException;
import com.victor.bookretail.repository.UserInfoRepository;
import com.victor.bookretail.service.point.PointCalculationManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

@Service
@Slf4j
public class UserService {

    @Resource
    private UserInfoRepository userInfoRepository;

    public UserInfoBo createUser(UserInfoBo userInfoBo) {
        UserInfoSearchBo searchBo = new UserInfoSearchBo().setPhone(userInfoBo.getPhone());
        if (Objects.nonNull(queryUser(searchBo))) {
            log.error("Duplicate phone number when create user, user info: {}", JSONUtil.toJsonStr(userInfoBo));
            throw new BusinessException(ResultCode.USER_EXISTED);
        }
        try {
            UserInfoPo userInfoPo = userInfoRepository.insert(UserInfoPo.fromBo(userInfoBo));
            return userInfoPo.toBo();
        } catch (Exception e) {
            log.error("Failed to create new user, user info: {}", JSONUtil.toJsonStr(userInfoBo), e);
            throw new BusinessException(ResultCode.FAILED_CREATE_USER);
        }
    }

    public UserInfoBo queryUser(UserInfoSearchBo searchBo) {
        UserInfoPo userInfoPo = userInfoRepository.queryOne(searchBo);
        return Objects.isNull(userInfoPo) ? null : userInfoPo.toBo();
    }

    public void updateUserPoint(OrderInfoBo orderInfoBo) {
        UserInfoSearchBo searchBo = new UserInfoSearchBo();
        searchBo.setId(orderInfoBo.getUserId());
        UserInfoPo userInfoPo = userInfoRepository.queryOne(searchBo);
        if (Objects.isNull(userInfoPo)) {
            log.error("Not found user info when update user point, user id: {}", orderInfoBo.getId());
            throw new BusinessException(ResultCode.FAILED_UPDATE_POINT);
        }
        int addPoint = PointCalculationManager.getPointCalculationByUserType(userInfoPo.getType())
                .calculate(new PointCalculateParameter().setAmount(orderInfoBo.getAmount().intValue()));
        Integer currentPoint = userInfoPo.getPoint();
        Integer updatePoint = currentPoint + addPoint;
        if (!userInfoRepository.updateUserPoint(userInfoPo, updatePoint)) {
            log.warn("Failed to update user point, user info: {}", JSONUtil.toJsonStr(userInfoPo));
            throw new BusinessException(ResultCode.FAILED_UPDATE_POINT);
        }
        log.info("Update user point successfully, update point: {}, user info: {}",
                updatePoint, JSONUtil.toJsonStr(userInfoPo));
    }

}
